// space.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>
#include "loadTexture.h"
#include "myTexture.h"
#include "changeSize.h"
#include "Sphare.h"
#include "Camera.h"
#include "Conversion.h"

#include "Skybox.h"
#include "Sphare.h"
#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/type_ptr.hpp>



using namespace std;
Skybox sky;
Sphere sun;
Camera cam;
float v1[3];
float v2[3];
float cross[3];

float angle=0;
float rotation[4]={0,0,0,0};
float lastPosition[3]={0,0,0};
//Quaternion rot(1,0,0,0);

bool mouse_pressed=false;
float last_x=0;
float last_y=0;

float current_x=0;
float current_y=0;




void Normalize(float* vec)
{
        float lenghtofVector3D=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
        lenghtofVector3D=sqrt(lenghtofVector3D);

        vec[0]/=lenghtofVector3D;
        vec[1]/=lenghtofVector3D;
        vec[2]/=lenghtofVector3D;
}

void CrossProduct(float *v1,float *v2,float* cross)
{
        //x = b*f - c*e , y = c*d - a*f and z = a*e - b*d       
        cross[0]=v1[1]*v2[2]-v1[2]*v2[1];
        cross[1]=v1[2]*v2[0]-v1[0]*v2[2];
        cross[2]=v1[0]*v2[1]-v1[1]*v2[0];

}

void PointOnBall(int x,int y,float* v)
{
	  
        int screenWidth = glutGet(GLUT_WINDOW_WIDTH);
        int screenHeight = glutGet(GLUT_WINDOW_HEIGHT);
        v[0]=(2.f*(float)x)/(float)screenWidth;
        v[0]-=1.f;

        v[1]=(2.f*(float)y)/(float)screenHeight;
        v[1]=1.f-v[1];

        float tempz=1.f-v[0]*v[0]+v[1]*v[1];
        v[2]= (tempz > 0.f) ? sqrt(tempz) : 0;
		

        Normalize(v);
		//cout<<v[0]<<" "<<v[1]<<" "<<v[2]<<endl;

}

float AngleBetween(float *v1,float *v2)
{
     
        float dot=v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
		float a=v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2];
        float b=v2[0]*v2[0]+v2[1]*v2[1]+v2[2]*v2[2];

        a=sqrt(a);
        b=sqrt(b);

        float ab=a*b;


        if(dot>1) 
        {
                dot=1;
        }
        else if(dot<-1)
        {
                dot=-1;
        }

        float theta=acos(dot/ab);

        return theta;
}

void onMouse(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		mouse_pressed=true;
		last_x=current_x=x;
		last_y=current_y=y;
		
	}
	else
	{
		mouse_pressed=false;
	}

	
}

glm::fquat camrot(1,0,0,0);
glm::mat4 rot;

void onMotion(int x, int y) 
{
  if (mouse_pressed==true) 
  { 
	current_x=x;
    current_y=y;
	if(current_x != last_x || current_y != last_y)
	{
		//cout<<x<<" "<<y<<endl;
		PointOnBall(last_x,last_y,v1);
		PointOnBall(current_x,current_y,v2);
		angle=AngleBetween(v1,v2);
		CrossProduct(v1,v2,cross);
		Normalize(cross);
		last_x=current_x;
		last_y=current_y;
		Quaternion q(angle,cross[0],cross[1],cross[2]);
		q=AxisAngleToQuaternion(angle*10,cross[0],cross[1],cross[2]);
		float* lol=q.GetArray();
	
		//cam.orientation=cam.orientation*q;
	
		glm::fquat q2(lol[0],lol[1],lol[2],lol[3]);
		//q2=glm::normalize(q2);
		camrot=camrot*q2;
		
		
		
		cout<<camrot.w<<" "<<camrot.x<<" "<<camrot.y<<" "<<camrot.z<<endl;
		rot=glm::mat4_cast(camrot);
		
		glutPostRedisplay();

	}
	
  }
}




void renderScene(void)
{
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	//cam.orientation=cam.orientation*EulerToQuaternion(0,1,0);
	//float *rot=cam.orientation.GetArray();
	

	gluLookAt(	cam.x,cam.y,cam.z,
				cam.x, 0, cam.z+20,
				0.0f, 1.0f,  0.0f);

	
	//float* rot=QuaternionToAxisAngle(cam.orientation);
	//float * rot=cam.orientation.GetArray();
	
	//cam.orientation.PrintQuaternion();
	//glRotatef(QuaternionToAngle(rot[0]),rot[1],rot[2],rot[3]);
		glMultMatrixf(glm::value_ptr(rot));

		glPushMatrix();
		glutWireTeapot(6);
		glColor3f(1,1,0);
		//glutSolidCube(2);
		glPopMatrix();

		

	glutSwapBuffers();
}

void processNormalKeys(unsigned char key, int x, int y) {

	switch(key)
	{
	case 27: exit(0); break;
	case 115: 
		{
			cam.z-=10.5;
			break;
		}
	case 100: 
		{
			cam.x+=5;
			break;
		}
	case 119: 
		{
			cam.z+=10;
			break;
		}
	case 97:
		{
			cam.x-=5;
			break;
		}

	}
	
}




int _tmain(int argc, _TCHAR* argv[])
{
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100,100);
	glutInitWindowSize(500,500);
	

	glutCreateWindow("GLSL");
	GLenum err = glewInit();

	 glEnable (GL_DEPTH_TEST);
	 glEnable (GL_TEXTURE_2D);
	
	const GLubyte* pVersion = glGetString(GL_VERSION);
	char* version=(char*)pVersion;
	cout<<"OPENGL "<<version<<" supported"<<endl;
	
	//sky=Skybox(0, 0, 0, 500, 500, 500);        
	cam=Camera(0,0,-50);

	glutReshapeFunc(changeSize);
	glutDisplayFunc(renderScene);
	glutIdleFunc(renderScene);

	glutKeyboardFunc(processNormalKeys);

	glutMotionFunc(onMotion);
	glutMouseFunc(onMouse);

	glutMainLoop();



	return 0;
}



